#include <iostream>
#include <vector>
#include <thread>
#include <mutex>

using namespace std;

namespace dsh
{
    template<class T>
    class shared_ptr
    {
    public:
        shared_ptr(T* ptr = nullptr)
            :_ptr(ptr)
            ,_pCount(new int(1)) // 初始化为1
            ,_pMutex(new mutex)
        {}

        ~shared_ptr()
        {
            Release();
        }

        void AddPCount()
        {
            _pMutex->lock();
            (*_pCount)++;
            _pMutex->unlock();
        }

        void Release()
        {
            bool flag = false; // 标识是不是最后一个，是的话也要释放锁
            _pMutex->lock();
            if (--(*_pCount) == 0) // 原来的是不是最后一个，是的话就释放
            {
                delete _ptr;
                delete _pCount;

                flag = true;
            }
            _pMutex->unlock();
            if (false)
                delete _pMutex;
        }

        // 拷贝构造
        shared_ptr(const shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            , _pCount(sp._pCount)
            , _pMutex(sp._pMutex)
        {
            AddPCount();
        }

        // 赋值
        shared_ptr& operator=(const shared_ptr<T>& sp)
        {
            if (sp._ptr != _ptr) // 不需要自己给自己赋值，也不需要给指向同一块的赋值
            {
                Release();

                _ptr = sp._ptr;
                _pCount = sp._pCount;
                _pMutex = sp._pMutex;
                AddPCount();
            }
            return *this;
        }
        int use_count()
        {
            return *_pCount;
        }
        T* get()
        {
            return _ptr;
        }
        T& operator*()
        {
            return *_ptr;
        }
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
        int* _pCount; // 引用计数
        mutex* _pMutex; // 锁
    };
}

int main()
{
    dsh::shared_ptr<int> sp1(new int(1));
    dsh::shared_ptr<int> sp2(sp1);

    vector<thread> v(2);
    int n = 10000000;
    for (auto& t : v)
    {
        t = thread([&](){
            for (size_t i = 0; i < n; i++)
            {
                dsh::shared_ptr<int> sp(sp1);

                (*sp)++;
            }
        });
    }
    v[0].join();
    v[1].join();
    cout << sp1.use_count() << endl;
    cout << sp1.get() << endl;
    cout << *sp1 << endl;

    return 0;
}